package com.sinszm.wx.pay.util;

import com.sinszm.common.exception.ApiException;
import com.sinszm.wx.pay.AbstractPay;
import com.sinszm.wx.pay.PayConstant;
import com.sinszm.wx.protocol.Wx;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;

import static com.sinszm.wx.exception.WxApiError.WX_PAY_ERROR_014;

/**
 * 支付调用工具
 *
 * @author chenjianbo
 */
public final class PayCallUtil {

    private PayCallUtil() {

    }

    public synchronized static Wx.Bean.PayResp unifiedorder(AbstractPay pay, Wx.Bean.PayReq payReq, Wx.Bean.SceneInfo scene, Wx.Bean.SceneInfoPro scenePro) {
        String[] contents = pay.fetchReqXml(payReq, scene, scenePro, null);
        String certKey = contents[0];
        String xmlBody = contents[1];
        SortedMap<String, String> response = PayRequest.post(
                pay.getUrl(PayConstant.UNIFIEDORDER),
                xmlBody,
                certKey,
                pay.getProperties().getSignType()
        );
        return pay.fetchRespBody(response);
    }

    public synchronized static Wx.Bean.PayResp notificationPaymentResult(AbstractPay pay, HttpServletRequest request, Wx.Bean.PayReq payReq) {
        String xml = pay.notifyParam(request);
        if (payReq == null) {
            return Wx.Bean.PayResp.newBuilder().build();
        }
        String certKey = payReq.getCertKey();
        if (StringUtils.isEmpty(certKey)) {
            throw new ApiException(WX_PAY_ERROR_014);
        }
        SortedMap<String, String> map = PayRequest.transform(xml, certKey, pay.getProperties().getSignType(), false);
        Wx.Bean.PayResp resp = pay.fetchRespBody(map);
        return orderquery(
                pay,
                payReq.toBuilder()
                        .setTransactionId(resp.getTransactionId())
                        .setOutTradeNo(resp.getOutTradeNo())
                        .build()
        );
    }

    public synchronized static Wx.Bean.PayResp orderquery(AbstractPay pay, Wx.Bean.PayReq payReq) {
        String[] contents = pay.fetchReqXml(payReq, null, null, null);
        String certKey = contents[0];
        String xmlBody = contents[1];
        SortedMap<String, String> response = PayRequest.post(
                pay.getUrl(PayConstant.ORDERQUERY),
                xmlBody,
                certKey,
                pay.getProperties().getSignType()
        );
        return pay.fetchRespBody(response);
    }

    public synchronized static Wx.Bean.PayResp closeorder(AbstractPay pay, Wx.Bean.PayReq payReq) {
        String[] contents = pay.fetchReqXml(payReq, null, null, null);
        String certKey = contents[0];
        String xmlBody = contents[1];
        SortedMap<String, String> response = PayRequest.post(
                pay.getUrl(PayConstant.CLOSEORDER),
                xmlBody,
                certKey,
                pay.getProperties().getSignType()
        );
        return pay.fetchRespBody(response);
    }

    public synchronized static Wx.Bean.PayResp refund(AbstractPay pay, Wx.Bean.PayReq payReq, InputStream cert) {
        payReq = payReq != null ? payReq.toBuilder().setNotifyUrl("").build() : null;
        String[] contents = pay.fetchReqXml(payReq, null, null, null);
        String certKey = contents[0];
        String xmlBody = contents[1];
        String mchId = contents[2];
        SortedMap<String, String> response = PayRequest.postBySSL(
                pay.getUrl(PayConstant.REFUND),
                xmlBody,
                mchId,
                cert,
                certKey,
                pay.getProperties().getSignType()
        );
        return pay.fetchRespBody(response);
    }

    public synchronized static Wx.Bean.PayResp refundquery(AbstractPay pay, Wx.Bean.PayReq payReq) {
        String[] contents = pay.fetchReqXml(payReq, null, null, null);
        String certKey = contents[0];
        String xmlBody = contents[1];
        SortedMap<String, String> response = PayRequest.post(
                pay.getUrl(PayConstant.REFUNDQUERY),
                xmlBody,
                certKey,
                pay.getProperties().getSignType()
        );
        return pay.fetchRespBody(response);
    }

    public synchronized static Wx.Bean.PayResp report(AbstractPay pay, Wx.Bean.PayReq payReq, List<Wx.Bean.Trades> trades, Map<String, String> changeKey) {
        String[] contents = pay.fetchReqXml(payReq, null, null, null, changeKey);
        String certKey = contents[0];
        String xmlBody = contents[1];
        SortedMap<String, String> response = PayRequest.post(
                pay.getUrl(PayConstant.REPORT),
                xmlBody,
                certKey,
                pay.getProperties().getSignType(),
                true
        );
        return pay.fetchRespBody(response);
    }

    public synchronized static Wx.Bean.PayResp batchquerycomment(AbstractPay pay, Wx.Bean.PayReq payReq, InputStream cert) {
        String[] contents = pay.fetchReqXml(payReq, null, null, null);
        String certKey = contents[0];
        String xmlBody = contents[1];
        String mchId = contents[2];
        SortedMap<String, String> response = PayRequest.postBySSL(
                pay.getUrl(PayConstant.BATCHQUERYCOMMENT),
                xmlBody,
                mchId,
                cert,
                certKey,
                pay.getProperties().getSignType(),
                true
        );
        return pay.fetchRespBody(response);
    }

}
